﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Linq.Expressions;
using EntityFramework.Extensions;
using Knlght.CH.Domain.IRepository;
using Knlght.Domain;
using Knlght.Repository.DBContext;

namespace Knlght.Repository.Base
{
    /// <summary>
    /// 仓储实现
    /// </summary>
    public class RepositoryBase : IRepositoryBase
    {
        private readonly EFDbContext _dbcontext = new EFDbContext();
        private DbTransaction DbTransaction { get; set; }
        public IRepositoryBase BeginTrans()
        {
            DbConnection dbConnection = ((IObjectContextAdapter)_dbcontext).ObjectContext.Connection;
            if (dbConnection.State == ConnectionState.Closed)
            {
                dbConnection.Open();
            }
            DbTransaction = dbConnection.BeginTransaction();
            return this;
        }
        public bool Commit()
        {
            try
            {
                var returnValue = _dbcontext.SaveChanges();
                DbTransaction?.Commit();
                return returnValue>0;
            }
            catch (Exception e)
            {
                DbTransaction?.Rollback();
                throw new EJApplicationException(e.Message);
            }
            finally
            {
                Dispose();
            }
        }
        public void Dispose()
        {
            DbTransaction?.Dispose();
            _dbcontext.Dispose();
        }

        public bool Insert<TModel>(TModel model) where TModel : class
        {
            _dbcontext.Entry(model).State = EntityState.Added;
            return DbTransaction == null && Commit();
        }
        public bool InsertToList<TModel>(List<TModel> models) where TModel : class
        {
            _dbcontext.BulkInsert(models);
            _dbcontext.BulkSaveChanges();
            return DbTransaction == null && Commit();
        }
        public bool Update<TModel>(TModel model) where TModel : class
        {
            switch (_dbcontext.Entry(model).State)
            {
                case EntityState.Modified:
                    return _dbcontext.SaveChanges() == 1;
                case EntityState.Detached:
                    try
                    {
                        _dbcontext.Set<TModel>().Attach(model);
                        _dbcontext.Entry(model).State = EntityState.Modified;
                    }
                    catch (InvalidOperationException e)
                    {
                        throw new EJApplicationException(e.Message);
                    }
                    return _dbcontext.SaveChanges() == 1;
                case EntityState.Unchanged:
                    break;
                case EntityState.Added:
                    break;
                case EntityState.Deleted:
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
            return DbTransaction == null && Commit();
        }

        #region 使用EF扩展EntityFramework.Extended 对数据进行批量更新，和批量删除
        public bool UpdateToList<TModel>(Expression<Func<TModel, bool>> predicate, Expression<Func<TModel, TModel>> key) where TModel : class
        {
            _dbcontext.Set<TModel>().Where(predicate).Update(key);
            return DbTransaction == null && Commit();
        }
        public bool Delete<TModel>(Expression<Func<TModel, bool>> predicate) where TModel : class
        {
            _dbcontext.Set<TModel>().Where(predicate).Delete();
            return DbTransaction == null && Commit();
        }
        #endregion


        public TModel GetModel<TModel>(object keyValue) where TModel : class
        {
            return _dbcontext.Set<TModel>().Find(keyValue);
        }
        public TModel GetModel<TModel>(Expression<Func<TModel, bool>> predicate) where TModel : class
        {
            return _dbcontext.Set<TModel>().FirstOrDefault(predicate);
        }
        public List<TModel> Getlist<TModel>() where TModel : class
        {
            return _dbcontext.Set<TModel>().ToList();
        }
        public List<TModel> GetList<TModel>(Expression<Func<TModel, bool>> predicate) where TModel : class
        {
            return _dbcontext.Set<TModel>().Where(predicate).ToList();
        }
        public List<TModel> GetList<TModel>(string strSql) where TModel : class
        {
            return _dbcontext.Database.SqlQuery<TModel>(strSql).ToList();
        }
        public List<TModel> GetList<TModel>(string strSql, object[] dbParameter) where TModel : class
        {
            return _dbcontext.Database.SqlQuery<TModel>(strSql, dbParameter).ToList();
        }
        
    }
}
